home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows 95 with MFC / Programming Windows 95 with MFC (Microsoft Programming Series)(097-0001465)(1996).iso / NT / CODE / CHAP14 / MTDEMO / MTDOC.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-05  |  9.5 KB  |  316 lines

  1. //***********************************************************************
  2. //
  3. //  MTDoc.cpp
  4. //
  5. //***********************************************************************
  6.  
  7. #include <afxwin.h>
  8. #include <afxmt.h>
  9. #include "Resource.h"
  10. #include "MTDoc.h"
  11.  
  12. UINT ThreadFunc (LPVOID);
  13. LOGPALETTE* CreateGrayScale ();
  14.  
  15. IMPLEMENT_DYNCREATE (CMTDoc, CDocument)
  16.  
  17. BEGIN_MESSAGE_MAP (CMTDoc, CDocument)
  18.     ON_COMMAND (ID_EFFECTS_GRAY_SCALE, OnGrayScale)
  19.     ON_UPDATE_COMMAND_UI (ID_EFFECTS_GRAY_SCALE, OnUpdateGrayScaleUI)
  20. END_MESSAGE_MAP ()
  21.  
  22. CMTDoc::CMTDoc ()
  23. {
  24.     m_hThread = NULL;
  25.     m_bWorking = FALSE;
  26. }
  27.  
  28. void CMTDoc::OnGrayScale ()
  29. {
  30.     if (!m_bWorking) {
  31.         m_threadParms.pWnd = AfxGetMainWnd ();
  32.         m_threadParms.pBitmap = &m_bitmap;
  33.         m_threadParms.pPalette = &m_palette;
  34.         m_threadParms.pCriticalSection = &m_criticalSection;
  35.         m_threadParms.pEvent = &m_event;
  36.  
  37.         m_bWorking = TRUE;
  38.         m_event.ResetEvent (); // Just to be sure
  39.         CWinThread* pThread = AfxBeginThread (ThreadFunc, &m_threadParms);
  40.         m_hThread = pThread->m_hThread;
  41.     }
  42.     else // Kill the thread
  43.         m_event.SetEvent ();
  44. }
  45.  
  46. void CMTDoc::ThreadFinished ()
  47. {
  48.     ::WaitForSingleObject (m_hThread, INFINITE);
  49.     m_bWorking = FALSE;
  50.  
  51.     if ((HPALETTE) m_palette != NULL) {
  52.         m_palette.DeleteObject ();
  53.         LOGPALETTE* pLP = CreateGrayScale ();
  54.         m_palette.CreatePalette (pLP);
  55.         delete[] pLP;
  56.     }
  57.     UpdateAllViews (NULL, 0, NULL);
  58. }
  59.  
  60. void CMTDoc::ThreadAborted ()
  61. {
  62.     ::WaitForSingleObject (m_hThread, INFINITE);
  63.     m_bWorking = FALSE;
  64. }
  65.  
  66. void CMTDoc::OnUpdateGrayScaleUI (CCmdUI* pCmdUI)
  67. {
  68.     if (m_bWorking) {
  69.         pCmdUI->SetText ("Stop &Gray Scale Conversion");
  70.         pCmdUI->Enable ();
  71.     }
  72.     else {
  73.         pCmdUI->SetText ("Convert to &Gray Scale");
  74.         pCmdUI->Enable ((HBITMAP) m_bitmap != NULL);
  75.     }
  76. }
  77.  
  78. BOOL CMTDoc::OnOpenDocument (LPCTSTR lpszPathName) 
  79. {
  80.     if (m_bWorking) {
  81.         AfxMessageBox ("You must stop the gray scale conversion " \
  82.             "before opening another document", MB_ICONSTOP | MB_OK);
  83.         return FALSE;
  84.     }
  85.  
  86.     if (!CDocument::OnOpenDocument (lpszPathName)) {
  87.         POSITION pos = GetFirstViewPosition ();
  88.         CView* pView = GetNextView (pos);
  89.         pView->OnInitialUpdate ();
  90.         return FALSE;
  91.     }
  92.  
  93.     // Return now if this device doesn't support palettes
  94.     CClientDC dc (AfxGetMainWnd ());
  95.     if ((dc.GetDeviceCaps (RASTERCAPS) & RC_PALETTE) == 0)
  96.         return TRUE;
  97.  
  98.     // Create a palette to go with the DIB section
  99.     if ((HBITMAP) m_bitmap != NULL) {
  100.         DIBSECTION ds;
  101.         m_bitmap.GetObject (sizeof (DIBSECTION), &ds);
  102.  
  103.         int nColors;
  104.         if (ds.dsBmih.biClrUsed != 0)
  105.             nColors = ds.dsBmih.biClrUsed;
  106.         else
  107.             nColors = 1 << ds.dsBmih.biBitCount;
  108.  
  109.         // Create a halftone palette if the DIB section contains more
  110.         // than 256 colors
  111.         if (nColors > 256)
  112.             m_palette.CreateHalftonePalette (&dc);
  113.  
  114.         // Create a custom palette from the DIB section's color table
  115.         // if the number of colors is 256 or less
  116.         else {
  117.             RGBQUAD* pRGB = new RGBQUAD[nColors];
  118.  
  119.             CDC memDC;
  120.             memDC.CreateCompatibleDC (&dc);
  121.             m_criticalSection.Lock ();
  122.             CBitmap* pOldBitmap = memDC.SelectObject (&m_bitmap);
  123.             ::GetDIBColorTable ((HDC) memDC, 0, nColors, pRGB);
  124.             memDC.SelectObject (pOldBitmap);
  125.             m_criticalSection.Unlock ();
  126.  
  127.             UINT nSize = sizeof (LOGPALETTE) +
  128.                 (sizeof (PALETTEENTRY) * (nColors - 1));
  129.             LOGPALETTE* pLP = (LOGPALETTE*) new BYTE[nSize];
  130.  
  131.             pLP->palVersion = 0x300;
  132.             pLP->palNumEntries = nColors;
  133.  
  134.             for (int i=0; i<nColors; i++) {
  135.                 pLP->palPalEntry[i].peRed = pRGB[i].rgbRed;
  136.                 pLP->palPalEntry[i].peGreen = pRGB[i].rgbGreen;
  137.                 pLP->palPalEntry[i].peBlue = pRGB[i].rgbBlue;
  138.                 pLP->palPalEntry[i].peFlags = 0;
  139.             }
  140.  
  141.             m_palette.CreatePalette (pLP);
  142.             delete[] pLP;
  143.             delete[] pRGB;
  144.         }
  145.     }
  146.     return TRUE;
  147. }
  148.  
  149. void CMTDoc::DeleteContents ()
  150. {
  151.     if ((HBITMAP) m_bitmap != NULL)
  152.         m_bitmap.DeleteObject ();
  153.  
  154.     if ((HPALETTE) m_palette != NULL)
  155.         m_palette.DeleteObject ();
  156.     
  157.     CDocument::DeleteContents();
  158. }
  159.  
  160. void CMTDoc::Serialize (CArchive& ar)
  161. {
  162.     if (ar.IsLoading ()) {
  163.         CString strFileName = ar.GetFile ()->GetFilePath ();
  164.  
  165.         HBITMAP hBitmap = (HBITMAP) ::LoadImage (AfxGetInstanceHandle (),
  166.             (LPCTSTR) strFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE |
  167.             LR_CREATEDIBSECTION);
  168.  
  169.         if (hBitmap == NULL)
  170.             AfxThrowArchiveException (CArchiveException::badIndex);
  171.  
  172.         m_bitmap.Attach (hBitmap);
  173.     }
  174. }
  175.  
  176. CBitmap* CMTDoc::GetBitmap ()
  177. {
  178.     return ((HBITMAP) m_bitmap == NULL) ? NULL : &m_bitmap;
  179. }
  180.  
  181. CPalette* CMTDoc::GetPalette ()
  182. {
  183.     return ((HPALETTE) m_palette == NULL) ? NULL : &m_palette;
  184. }
  185.  
  186. /////////////////////////////////////////////////////////////////////////
  187. // Thread function and other globals
  188.  
  189. UINT ThreadFunc (LPVOID pParam)
  190. {
  191.     THREADPARMS* pThreadParms = (THREADPARMS*) pParam;
  192.     CWnd* pWnd = pThreadParms->pWnd;
  193.     CBitmap* pBitmap = pThreadParms->pBitmap;
  194.     CPalette* pPalette = pThreadParms->pPalette;
  195.     CCriticalSection* pCriticalSection = pThreadParms->pCriticalSection;
  196.     CEvent* pKillThread = pThreadParms->pEvent;
  197.  
  198.     DIBSECTION ds;
  199.     pBitmap->GetObject (sizeof (DIBSECTION), &ds);
  200.     int nWidth = ds.dsBm.bmWidth;
  201.     int nHeight = ds.dsBm.bmHeight;
  202.  
  203.     // Initialize one memory DC (memDC2) to hold a color copy of the
  204.     // image and another memory DC (memDC1) to hold a gray scale copy
  205.     CClientDC dc (pWnd);
  206.     CBitmap bitmap1, bitmap2;
  207.     bitmap1.CreateCompatibleBitmap (&dc, nWidth, nHeight);
  208.     bitmap2.CreateCompatibleBitmap (&dc, nWidth, nHeight);
  209.  
  210.     CDC memDC1, memDC2;
  211.     memDC1.CreateCompatibleDC (&dc);
  212.     memDC2.CreateCompatibleDC (&dc);
  213.     CBitmap* pOldBitmap1 = memDC1.SelectObject (&bitmap1);
  214.     CBitmap* pOldBitmap2 = memDC2.SelectObject (&bitmap2);
  215.  
  216.     CPalette* pOldPalette1 = NULL;
  217.     CPalette* pOldPalette2 = NULL;
  218.     CPalette grayPalette;
  219.  
  220.     if (pPalette->m_hObject != NULL) {
  221.         LOGPALETTE* pLP = CreateGrayScale ();
  222.         grayPalette.CreatePalette (pLP);
  223.         delete[] pLP;
  224.  
  225.         pOldPalette1 = memDC1.SelectPalette (&grayPalette, FALSE);
  226.         pOldPalette2 = memDC2.SelectPalette (pPalette, FALSE);
  227.         memDC1.RealizePalette ();
  228.         memDC2.RealizePalette ();
  229.     }
  230.  
  231.     // Copy the bitmap to memDC2
  232.     CDC memDC3;
  233.     memDC3.CreateCompatibleDC (&dc);
  234.     pCriticalSection->Lock ();
  235.     CBitmap* pOldBitmap3 = memDC3.SelectObject (pBitmap);
  236.     memDC2.BitBlt (0, 0, nWidth, nHeight, &memDC3, 0, 0, SRCCOPY);
  237.     memDC3.SelectObject (pOldBitmap3);
  238.     pCriticalSection->Unlock ();
  239.  
  240.     // Convert the colors in memDC2 to shades of gray in memDC1
  241.     int x, y;
  242.     COLORREF crColor;
  243.     BYTE grayLevel;
  244.  
  245.     for (y=0; y<nHeight; y++) {
  246.         for (x=0; x<nWidth; x++) {
  247.             crColor = memDC2.GetPixel (x, y);
  248.             grayLevel = (BYTE)
  249.                 (((((UINT) GetRValue (crColor)) * 30) +
  250.                 (((UINT) GetGValue (crColor)) * 59) +
  251.                 (((UINT) GetBValue (crColor)) * 11)) / 100);
  252.             memDC1.SetPixel (x, y,
  253.                 PALETTERGB (grayLevel, grayLevel, grayLevel));
  254.         }
  255.  
  256.         // Kill the thread if the pKillThread event is signaled
  257.         if (::WaitForSingleObject (pKillThread->m_hObject, 0) ==
  258.             WAIT_OBJECT_0) {
  259.  
  260.             memDC1.SelectObject (pOldBitmap1);
  261.             memDC2.SelectObject (pOldBitmap2);
  262.  
  263.             if (pPalette->m_hObject != NULL) {
  264.                 memDC1.SelectPalette (pOldPalette1, FALSE);
  265.                 memDC2.SelectPalette (pOldPalette2, FALSE);
  266.             }
  267.             pWnd->PostMessage (WM_USER_THREAD_ABORTED, y + 1, 0);
  268.             return (UINT) -1;
  269.         }
  270.         pWnd->PostMessage (WM_USER_THREAD_UPDATE, y + 1, nHeight);
  271.     }
  272.  
  273.     // Copy the gray scale image over the original bitmap
  274.     CPalette* pOldPalette3 = NULL;
  275.     if (pPalette->m_hObject != NULL) {
  276.         pOldPalette3 = memDC3.SelectPalette (&grayPalette, FALSE);
  277.         memDC3.RealizePalette ();
  278.     }
  279.     pCriticalSection->Lock ();
  280.     pOldBitmap3 = memDC3.SelectObject (pBitmap);
  281.     memDC3.BitBlt (0, 0, nWidth, nHeight, &memDC1, 0, 0, SRCCOPY);
  282.     memDC3.SelectObject (pOldBitmap3);
  283.     pCriticalSection->Unlock ();
  284.  
  285.     // Clean up the memory DCs
  286.     memDC1.SelectObject (pOldBitmap1);
  287.     memDC2.SelectObject (pOldBitmap2);
  288.  
  289.     if (pPalette->m_hObject != NULL) {
  290.         memDC1.SelectPalette (pOldPalette1, FALSE);
  291.         memDC2.SelectPalette (pOldPalette2, FALSE);
  292.         memDC3.SelectPalette (pOldPalette3, FALSE);
  293.     }
  294.  
  295.     // Tell the frame window we're done
  296.     pWnd->PostMessage (WM_USER_THREAD_FINISHED, 0, 0);
  297.     return 0;
  298. }
  299.  
  300. LOGPALETTE* CreateGrayScale ()
  301. {
  302.     UINT nSize = sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 63);
  303.     LOGPALETTE* pLP = (LOGPALETTE*) new BYTE[nSize];
  304.  
  305.     pLP->palVersion = 0x300;
  306.     pLP->palNumEntries = 64;
  307.  
  308.     for (int i=0; i<64; i++) {
  309.         pLP->palPalEntry[i].peRed = i * 4;
  310.         pLP->palPalEntry[i].peGreen = i * 4;
  311.         pLP->palPalEntry[i].peBlue = i * 4;
  312.         pLP->palPalEntry[i].peFlags = 0;
  313.     }
  314.     return pLP;
  315. }
  316.